"""
语义分析器 V3.0
完全重新设计，实现完整的类型检查和语义验证
"""

from typing import Dict, Any, List, Optional, Set
import json

class SemanticAnalyzerV3:
    """语义分析器 V3.0"""
    
    def __init__(self):
        """初始化语义分析器"""
        self.catalog = {}  # 系统目录
        self.errors = []
        self.warnings = []
        
        # 支持的数据类型
        self.supported_types = {
            'int': {'size': 4, 'default': 0},
            'integer': {'size': 4, 'default': 0},
            'varchar': {'size': 'variable', 'default': ''},
            'char': {'size': 'variable', 'default': ''},
            'float': {'size': 8, 'default': 0.0},
            'double': {'size': 8, 'default': 0.0},
            'boolean': {'size': 1, 'default': False},
            'bool': {'size': 1, 'default': False},
            'date': {'size': 10, 'default': '1900-01-01'},
            'time': {'size': 8, 'default': '00:00:00'},
            'datetime': {'size': 19, 'default': '1900-01-01 00:00:00'}
        }
    
    def analyze(self, ast: Dict[str, Any]) -> Dict[str, Any]:
        """进行语义分析"""
        self.errors = []
        self.warnings = []
        
        if not ast:
            self.errors.append("AST为空，无法进行语义分析")
            return {'valid': False, 'errors': self.errors}
        
        try:
            if ast['type'] == 'CREATE_TABLE':
                return self._analyze_create_table(ast)
            elif ast['type'] == 'INSERT':
                return self._analyze_insert(ast)
            elif ast['type'] == 'SELECT':
                return self._analyze_select(ast)
            elif ast['type'] == 'DELETE':
                return self._analyze_delete(ast)
            elif ast['type'] == 'UPDATE':
                return self._analyze_update(ast)
            elif ast['type'] == 'DROP_TABLE':
                return self._analyze_drop_table(ast)
            else:
                self.errors.append(f"不支持的语句类型: {ast['type']}")
                return {'valid': False, 'errors': self.errors}
        
        except Exception as e:
            self.errors.append(f"语义分析异常: {str(e)}")
            return {'valid': False, 'errors': self.errors}
    
    def _analyze_create_table(self, ast: Dict[str, Any]) -> Dict[str, Any]:
        """分析CREATE TABLE语句"""
        table_name = ast['table_name']
        
        # 检查表名是否已存在
        if table_name in self.catalog:
            self.errors.append(f"表 '{table_name}' 已存在")
            return {'valid': False, 'errors': self.errors}
        
        # 验证列定义
        columns = {}
        primary_keys = []
        
        for col_def in ast['columns']:
            col_name = col_def['name']
            
            # 检查列名重复
            if col_name in columns:
                self.errors.append(f"列名 '{col_name}' 重复")
                continue
            
            # 验证数据类型
            col_type = col_def['type']
            if col_type['type'] not in self.supported_types:
                self.errors.append(f"不支持的数据类型: {col_type['type']}")
                continue
            
            # 处理约束
            constraints = col_def.get('constraints', [])
            is_primary = False
            is_not_null = False
            default_value = None
            
            for constraint in constraints:
                if constraint['type'] == 'PRIMARY_KEY':
                    is_primary = True
                    primary_keys.append(col_name)
                elif constraint['type'] == 'NOT_NULL':
                    is_not_null = True
                elif constraint['type'] == 'DEFAULT':
                    default_value = constraint['value']
            
            # 构建列信息
            columns[col_name] = {
                'type': col_type,
                'primary_key': is_primary,
                'not_null': is_not_null,
                'default': default_value
            }
        
        # 检查主键约束
        if len(primary_keys) > 1:
            self.errors.append("一个表只能有一个主键")
        elif len(primary_keys) == 1:
            # 主键自动设置为NOT NULL
            columns[primary_keys[0]]['not_null'] = True
        
        if self.errors:
            return {'valid': False, 'errors': self.errors}
        
        # 创建表结构
        table_schema = {
            'columns': columns,
            'primary_key': primary_keys[0] if primary_keys else None,
            'created_at': self._get_current_time()
        }
        
        # 添加到系统目录
        self.catalog[table_name] = table_schema
        
        return {
            'valid': True,
            'table_name': table_name,
            'schema': table_schema,
            'warnings': self.warnings
        }
    
    def _analyze_insert(self, ast: Dict[str, Any]) -> Dict[str, Any]:
        """分析INSERT语句"""
        table_name = ast['table_name']
        
        # 检查表是否存在
        if table_name not in self.catalog:
            self.errors.append(f"表 '{table_name}' 不存在")
            return {'valid': False, 'errors': self.errors}
        
        table_schema = self.catalog[table_name]
        columns = table_schema['columns']
        
        # 确定要插入的列
        if ast['columns']:
            # 指定列名
            insert_columns = ast['columns']
            for col_name in insert_columns:
                if col_name not in columns:
                    self.errors.append(f"列 '{col_name}' 不存在")
        else:
            # 插入所有列
            insert_columns = list(columns.keys())
        
        # 检查值的数量
        values = ast['values']
        if len(values) != len(insert_columns):
            self.errors.append(f"值的数量 ({len(values)}) 与列的数量 ({len(insert_columns)}) 不匹配")
            return {'valid': False, 'errors': self.errors}
        
        # 类型检查
        for i, (col_name, value) in enumerate(zip(insert_columns, values)):
            col_type = columns[col_name]['type']['type']
            value_type = value['type']
            
            if not self._is_type_compatible(col_type, value_type, value['value']):
                self.errors.append(f"列 '{col_name}' 类型不匹配: 期望 {col_type}, 得到 {value_type}")
        
        if self.errors:
            return {'valid': False, 'errors': self.errors}
        
        return {
            'valid': True,
            'table_name': table_name,
            'columns': insert_columns,
            'values': values,
            'warnings': self.warnings
        }
    
    def _analyze_select(self, ast: Dict[str, Any]) -> Dict[str, Any]:
        """分析SELECT语句"""
        table_name = ast['table_name']
        
        # 检查表是否存在
        if table_name not in self.catalog:
            self.errors.append(f"表 '{table_name}' 不存在")
            return {'valid': False, 'errors': self.errors}
        
        table_schema = self.catalog[table_name]
        columns = table_schema['columns']
        
        # 处理GROUP BY, HAVING和ORDER BY
        group_by = ast.get('group_by', [])
        having_clause = ast.get('having_clause')
        order_by = ast.get('order_by', [])
        
        # 确定选择的列和表达式
        selected_columns = []
        select_expressions = ast['columns']
        aggregate_columns = []
        alias_map = {}
        
        # 特殊处理星号情况
        if isinstance(select_expressions, dict) and select_expressions.get('type') == 'ALL_COLUMNS':
            # 星号表示选择所有列
            selected_columns = list(columns.keys())
        elif select_expressions == '*':
            # 兼容旧版本的简单'*'字符串
            selected_columns = list(columns.keys())
        else:
            # 处理列表达式
            for expr in select_expressions:
                if isinstance(expr, dict):
                    # 处理复杂表达式（如带别名或聚合函数）
                    if expr.get('type') == 'AGGREGATE':
                        func_name = expr['function']
                        col_name = expr.get('column', expr.get('argument'))
                        
                        # 检查COUNT(*)特殊情况
                        if func_name == 'COUNT' and col_name == '*':
                            aggregate_columns.append(expr)
                        # 检查列是否存在
                        elif col_name not in columns and col_name != '*':
                            self.errors.append(f"列 '{col_name}' 不存在")
                        else:
                            aggregate_columns.append(expr)
                    elif expr.get('type') == 'COLUMN':
                        col_name = expr['name']
                        if col_name not in columns:
                            self.errors.append(f"列 '{col_name}' 不存在")
                        
                        # 处理别名
                        if 'alias' in expr:
                            alias_map[expr['alias']] = col_name
                            selected_columns.append(expr['alias'])
                        else:
                            selected_columns.append(col_name)
                else:
                    # 简单列名
                    col_name = expr
                    if col_name not in columns:
                        self.errors.append(f"列 '{col_name}' 不存在")
                    selected_columns.append(col_name)
        
        # 分析GROUP BY子句
        if group_by:
            for col_name in group_by:
                if col_name not in columns and col_name not in alias_map:
                    self.errors.append(f"GROUP BY中的列 '{col_name}' 不存在")
            
            # 检查SELECT列是否与GROUP BY兼容
            for expr in selected_columns:
                # 如果不是星号且不是聚合函数列且不在GROUP BY中，则报错
                if (select_expressions != '*' and 
                    expr not in group_by and 
                    expr not in alias_map.values() and 
                    not any(agg.get('alias') == expr or agg.get('column') == expr for agg in aggregate_columns)):
                    self.errors.append(f"列 '{expr}' 未包含在GROUP BY子句中，也不是聚合函数")
        
        # 分析WHERE条件
        where_clause = None
        if ast['where_clause']:
            where_result = self._analyze_condition(ast['where_clause'], columns, alias_map=alias_map)
            if not where_result['valid']:
                self.errors.extend(where_result['errors'])
            else:
                where_clause = where_result['condition']
        
        # 分析HAVING条件
        having_clause = None
        if ast.get('having_clause'):
            having_result = self._analyze_condition(ast['having_clause'], columns, alias_map=alias_map, 
                                                   is_having=True, group_by_columns=group_by, 
                                                   aggregate_columns=aggregate_columns)
            if not having_result['valid']:
                self.errors.extend(having_result['errors'])
            else:
                having_clause = having_result['condition']
        
        # 分析ORDER BY子句
        if order_by:
            for order_expr in order_by:
                col_name = order_expr['column']
                # 检查列是否存在于选择的列中或表中
                if (col_name not in selected_columns and 
                    col_name not in columns and 
                    col_name not in alias_map):
                    self.errors.append(f"ORDER BY中的列 '{col_name}' 不存在")
        
        if self.errors:
            return {'valid': False, 'errors': self.errors}
        
        return {
            'valid': True,
            'table_name': table_name,
            'columns': selected_columns,
            'where_clause': where_clause,
            'group_by': group_by,
            'having_clause': having_clause,
            'order_by': order_by,
            'aggregate_columns': aggregate_columns,
            'alias_map': alias_map,
            'warnings': self.warnings
        }
    
    def _analyze_delete(self, ast: Dict[str, Any]) -> Dict[str, Any]:
        """分析DELETE语句"""
        table_name = ast['table_name']
        
        # 检查表是否存在
        if table_name not in self.catalog:
            self.errors.append(f"表 '{table_name}' 不存在")
            return {'valid': False, 'errors': self.errors}
        
        table_schema = self.catalog[table_name]
        columns = table_schema['columns']
        
        # 分析WHERE条件
        where_clause = None
        if ast['where_clause']:
            where_result = self._analyze_condition(ast['where_clause'], columns)
            if not where_result['valid']:
                self.errors.extend(where_result['errors'])
            else:
                where_clause = where_result['condition']
        
        if self.errors:
            return {'valid': False, 'errors': self.errors}
        
        return {
            'valid': True,
            'table_name': table_name,
            'where_clause': where_clause,
            'warnings': self.warnings
        }
    
    def _analyze_update(self, ast: Dict[str, Any]) -> Dict[str, Any]:
        """分析UPDATE语句"""
        table_name = ast['table_name']
        
        # 检查表是否存在
        if table_name not in self.catalog:
            self.errors.append(f"表 '{table_name}' 不存在")
            return {'valid': False, 'errors': self.errors}
        
        table_schema = self.catalog[table_name]
        columns = table_schema['columns']
        
        # 检查SET子句中的列
        assignments = ast['assignments']
        for assignment in assignments:
            col_name = assignment['column']
            if col_name not in columns:
                self.errors.append(f"列 '{col_name}' 不存在")
                continue
            
            # 类型检查
            col_type = columns[col_name]['type']['type']
            value = assignment['value']
            if not self._is_type_compatible(col_type, value['type'], value['value']):
                self.errors.append(f"列 '{col_name}' 类型不匹配: 期望 {col_type}, 得到 {value['type']}")
        
        # 分析WHERE条件
        where_clause = None
        if ast['where_clause']:
            where_result = self._analyze_condition(ast['where_clause'], columns)
            if not where_result['valid']:
                self.errors.extend(where_result['errors'])
            else:
                where_clause = where_result['condition']
        
        if self.errors:
            return {'valid': False, 'errors': self.errors}
        
        return {
            'valid': True,
            'table_name': table_name,
            'assignments': assignments,
            'where_clause': where_clause,
            'warnings': self.warnings
        }
    
    def _analyze_drop_table(self, ast: Dict[str, Any]) -> Dict[str, Any]:
        """分析DROP TABLE语句"""
        table_name = ast['table_name']
        
        # 检查表是否存在
        if table_name not in self.catalog:
            self.errors.append(f"表 '{table_name}' 不存在")
            return {'valid': False, 'errors': self.errors}
        
        del self.catalog[table_name] #从系统目录中删除表元数据

        return {
            'valid': True,
            'table_name': table_name,
            'warnings': self.warnings
        }
    
    def _analyze_condition(self, condition: Dict[str, Any], columns: Dict[str, Any], 
                          alias_map: Optional[Dict[str, str]] = None, 
                          is_having: bool = False, 
                          group_by_columns: Optional[List[str]] = None, 
                          aggregate_columns: Optional[List[Dict[str, Any]]] = None) -> Dict[str, Any]:
        """分析WHERE/HAVING条件"""
        if alias_map is None:
            alias_map = {}
        if group_by_columns is None:
            group_by_columns = []
        if aggregate_columns is None:
            aggregate_columns = []
            
        if condition['type'] == 'COMPARISON':
            # 检查列是否存在
            left = condition['left']
            right = condition['right']
            
            # 检查左侧操作数
            if left['type'] == 'COLUMN':
                col_name = left['name']
                # 检查列是否存在于表中或别名映射中
                if col_name not in columns:
                    # 检查是否是别名
                    if col_name in alias_map:
                        # 别名存在，获取原始列名
                        original_col_name = alias_map[col_name]
                        if original_col_name not in columns:
                            return {'valid': False, 'errors': [f"别名 '{col_name}' 对应的列不存在"]}
                    # 不是别名，在HAVING条件中允许引用聚合函数
                    elif is_having:
                        # 检查是否是聚合函数
                        is_aggregate = any(
                            agg.get('alias') == col_name or 
                            (agg['function'] == 'COUNT' and agg['column'] == '*') or 
                            f"{agg['function']}({agg['column']})" == col_name 
                            for agg in aggregate_columns
                        )
                        if not is_aggregate and col_name not in group_by_columns:
                            return {'valid': False, 'errors': [f"列 '{col_name}' 在表中不存在，也不是有效的聚合表达式"]}
                    else:
                        return {'valid': False, 'errors': [f"列 '{col_name}' 不存在"]}
            
            # 检查右侧操作数
            if right['type'] == 'COLUMN':
                col_name = right['name']
                # 检查列是否存在于表中或别名映射中
                if col_name not in columns:
                    if col_name in alias_map:
                        original_col_name = alias_map[col_name]
                        if original_col_name not in columns:
                            return {'valid': False, 'errors': [f"别名 '{col_name}' 对应的列不存在"]}
                    elif is_having:
                        is_aggregate = any(
                            agg.get('alias') == col_name or 
                            (agg['function'] == 'COUNT' and agg['column'] == '*') or 
                            f"{agg['function']}({agg['column']})" == col_name 
                            for agg in aggregate_columns
                        )
                        if not is_aggregate and col_name not in group_by_columns:
                            return {'valid': False, 'errors': [f"列 '{col_name}' 在表中不存在，也不是有效的聚合表达式"]}
                    else:
                        return {'valid': False, 'errors': [f"列 '{col_name}' 不存在"]}
            
            return {'valid': True, 'condition': condition}
        
        elif condition['type'] == 'LOGICAL':
            if condition['operator'] == 'NOT':
                result = self._analyze_condition(condition['operand'], columns, alias_map, is_having, group_by_columns, aggregate_columns)
                if not result['valid']:
                    return result
                return {'valid': True, 'condition': condition}
            else:
                left_result = self._analyze_condition(condition['left'], columns, alias_map, is_having, group_by_columns, aggregate_columns)
                right_result = self._analyze_condition(condition['right'], columns, alias_map, is_having, group_by_columns, aggregate_columns)
                
                errors = []
                if not left_result['valid']:
                    errors.extend(left_result['errors'])
                if not right_result['valid']:
                    errors.extend(right_result['errors'])
                
                if errors:
                    return {'valid': False, 'errors': errors}
                
                return {'valid': True, 'condition': condition}
        
        elif condition['type'] == 'BETWEEN':
            # 检查BETWEEN条件中的表达式
            expr = condition['expression']
            lower = condition['lower']
            upper = condition['upper']
            
            # 检查表达式是否是有效的列引用
            if expr['type'] == 'COLUMN':
                col_name = expr['name']
                if col_name not in columns:
                    if col_name in alias_map:
                        original_col_name = alias_map[col_name]
                        if original_col_name not in columns:
                            return {'valid': False, 'errors': [f"别名 '{col_name}' 对应的列不存在"]}
                    elif is_having:
                        is_aggregate = any(
                            agg.get('alias') == col_name or 
                            (agg['function'] == 'COUNT' and agg['column'] == '*') or 
                            f"{agg['function']}({agg['column']})" == col_name 
                            for agg in aggregate_columns
                        )
                        if not is_aggregate and col_name not in group_by_columns:
                            return {'valid': False, 'errors': [f"列 '{col_name}' 在表中不存在，也不是有效的聚合表达式"]}
                    else:
                        return {'valid': False, 'errors': [f"列 '{col_name}' 不存在"]}
            
            # 检查下边界
            if lower['type'] == 'COLUMN':
                col_name = lower['name']
                if col_name not in columns:
                    if col_name in alias_map:
                        original_col_name = alias_map[col_name]
                        if original_col_name not in columns:
                            return {'valid': False, 'errors': [f"别名 '{col_name}' 对应的列不存在"]}
                    elif is_having:
                        is_aggregate = any(
                            agg.get('alias') == col_name or 
                            (agg['function'] == 'COUNT' and agg['column'] == '*') or 
                            f"{agg['function']}({agg['column']})" == col_name 
                            for agg in aggregate_columns
                        )
                        if not is_aggregate and col_name not in group_by_columns:
                            return {'valid': False, 'errors': [f"列 '{col_name}' 在表中不存在，也不是有效的聚合表达式"]}
                    else:
                        return {'valid': False, 'errors': [f"列 '{col_name}' 不存在"]}
            
            # 检查上边界
            if upper['type'] == 'COLUMN':
                col_name = upper['name']
                if col_name not in columns:
                    if col_name in alias_map:
                        original_col_name = alias_map[col_name]
                        if original_col_name not in columns:
                            return {'valid': False, 'errors': [f"别名 '{col_name}' 对应的列不存在"]}
                    elif is_having:
                        is_aggregate = any(
                            agg.get('alias') == col_name or 
                            (agg['function'] == 'COUNT' and agg['column'] == '*') or 
                            f"{agg['function']}({agg['column']})" == col_name 
                            for agg in aggregate_columns
                        )
                        if not is_aggregate and col_name not in group_by_columns:
                            return {'valid': False, 'errors': [f"列 '{col_name}' 在表中不存在，也不是有效的聚合表达式"]}
                    else:
                        return {'valid': False, 'errors': [f"列 '{col_name}' 不存在"]}
            
            return {'valid': True, 'condition': condition}
        
        return {'valid': True, 'condition': condition}
    
    def _is_type_compatible(self, expected_type: str, actual_type: str, value: Any) -> bool:
        """检查类型兼容性"""
        if actual_type == 'NULL':
            return True  # NULL可以赋值给任何类型
        
        if expected_type in ['int', 'integer']:
            return actual_type == 'NUMBER' and isinstance(value, int)
        elif expected_type in ['float', 'double']:
            return actual_type == 'NUMBER'
        elif expected_type in ['varchar', 'char']:
            return actual_type == 'STRING'
        elif expected_type in ['boolean', 'bool']:
            return actual_type == 'BOOLEAN'
        elif expected_type in ['date', 'time', 'datetime']:
            return actual_type == 'STRING'
        
        return False
    
    def _get_current_time(self) -> str:
        """获取当前时间字符串"""
        import time
        return str(int(time.time()))
    
    def get_catalog(self) -> Dict[str, Any]:
        """获取系统目录"""
        return self.catalog
    
    def print_catalog(self):
        """打印系统目录"""
        print("系统目录:")
        print("-" * 60)
        
        if not self.catalog:
            print("目录为空")
            return
        
        for table_name, schema in self.catalog.items():
            print(f"表: {table_name}")
            print(f"  创建时间: {schema['created_at']}")
            if schema['primary_key']:
                print(f"  主键: {schema['primary_key']}")
            print("  列:")
            for col_name, col_info in schema['columns'].items():
                col_type = col_info['type']['type']
                if col_info['type'].get('length'):
                    col_type += f"({col_info['type']['length']})"
                
                constraints = []
                if col_info['primary_key']:
                    constraints.append("PRIMARY KEY")
                if col_info['not_null']:
                    constraints.append("NOT NULL")
                if col_info['default'] is not None:
                    constraints.append(f"DEFAULT {col_info['default']}")
                
                constraint_str = f" ({', '.join(constraints)})" if constraints else ""
                print(f"    {col_name}: {col_type}{constraint_str}")
            print()

def main():
    """测试语义分析器"""
    analyzer = SemanticAnalyzerV3()
    
    # 测试SQL语句
    test_sqls = [
        "CREATE TABLE tst1 (id INT, name VARCHAR(50), age INT);",
        "INSERT INTO tst1 VALUES (1, 'Alice', 25);",
        "SELECT * FROM tst1 WHERE age > 20;",
        "DELETE FROM tst1 WHERE age > 20;"
    ]
    
    for sql in test_sqls:
        print(f"分析SQL: {sql}")
        print("-" * 60)
        
        # 这里需要先进行词法和语法分析
        # 为了测试，我们直接构造AST
        if "CREATE TABLE" in sql:
            ast = {
                'type': 'CREATE_TABLE',
                'table_name': 'tst1',
                'columns': [
                    {'name': 'id', 'type': {'type': 'int'}, 'constraints': []},
                    {'name': 'name', 'type': {'type': 'varchar', 'length': 50}, 'constraints': []},
                    {'name': 'age', 'type': {'type': 'int'}, 'constraints': []}
                ]
            }
        elif "INSERT" in sql:
            ast = {
                'type': 'INSERT',
                'table_name': 'tst1',
                'columns': None,
                'values': [
                    {'type': 'NUMBER', 'value': 1},
                    {'type': 'STRING', 'value': 'Alice'},
                    {'type': 'NUMBER', 'value': 25}
                ]
            }
        elif "SELECT" in sql:
            ast = {
                'type': 'SELECT',
                'table_name': 'tst1',
                'columns': '*',
                'where_clause': {
                    'type': 'COMPARISON',
                    'operator': '>',
                    'left': {'type': 'COLUMN', 'name': 'age'},
                    'right': {'type': 'NUMBER', 'value': 20}
                }
            }
        elif "DELETE" in sql:
            ast = {
                'type': 'DELETE',
                'table_name': 'tst1',
                'where_clause': {
                    'type': 'COMPARISON',
                    'operator': '>',
                    'left': {'type': 'COLUMN', 'name': 'age'},
                    'right': {'type': 'NUMBER', 'value': 20}
                }
            }
        
        result = analyzer.analyze(ast)
        if result['valid']:
            print("语义分析通过")
            if result.get('warnings'):
                print("警告:")
                for warning in result['warnings']:
                    print(f"  - {warning}")
        else:
            print("语义分析失败:")
            for error in result['errors']:
                print(f"  - {error}")
        
        print("\n" + "="*80 + "\n")
    
    # 打印系统目录
    analyzer.print_catalog()

if __name__ == "__main__":
    main()